/* 
 *File: parser.c
 * ------------------------
 * This file implements the parse interface.
 *
 * Authors: Olof Ivarsson och Johanna Carlsson
 */

#include <stdio.h>
#include <ctype.h>
#include "genlib.h"
#include "strlib.h"
#include "simpio.h"
#include "scanadt.h"
#include "parser.h"
#include "exp.h"

/* function prototypes */
static expADT parseIf(scannerADT scanner);
static expADT parseFunc(scannerADT scanner);

/*
 * Function: parseExp
 * Usage: exp = parseExp(scanner);
 * ------------------------------
 * This function starts the parsing of an expression and returns it.
 */
expADT parseExp(scannerADT scanner){
	expADT exp;

	exp = readE(scanner);
	if(MoreTokensExist(scanner))
		Error("ParseExp: %s unexpected", ReadToken(scanner));
	
	return exp;
}

/*
 * Function: readE
 * Usage: exp = readE(scanner);
 * ------------------------------
 * This function parse an expression and returns it.
 */
expADT readE(scannerADT scanner){
	expADT exp, rhs;
	string token;
	
	exp = readT(scanner);
	token = ReadToken(scanner);
	if(StringEqual(token, "+") || StringEqual(token, "-")){
		rhs = readE(scanner);
		exp = NewCompoundExp(IthChar(token, 0), exp, rhs);
	} else {
		SaveToken(scanner, token);
	}

	return exp;
}

/*
 * Function: readT
 * Usage: exp = readT(scanner);
 * ------------------------------
 * This function parse an term and returns it.
 */
expADT readT(scannerADT scanner){
	expADT exp, rhs;
	string token;
	
	exp = readC(scanner);
	token = ReadToken(scanner);
	if(StringEqual(token, "*") || StringEqual(token, "/")){
		rhs = readT(scanner);
		exp = NewCompoundExp(IthChar(token, 0), exp, rhs);
	} else {
		SaveToken(scanner, token);
	}

	return exp;
}

/*
 * Function: readC
 * Usage: exp = readC(scanner);
 * ------------------------------
 * This function parse an call and returns it.
 */
expADT readC(scannerADT scanner){
	expADT exp, arg;
	string token;
	
	exp = readF(scanner);
	token = ReadToken(scanner);
	if(StringEqual(token, "(")){
		arg = readE(scanner);
		if (!StringEqual(ReadToken(scanner), ")")) {
            Error("Unbalanced parentheses");
        }
		exp = NewCallExp(exp, arg);
	} else {
		SaveToken(scanner, token);
	}	

	return exp;
}

/*
 * Function: readF
 * Usage: exp = readF(scanner);
 * ------------------------------
 * This function parse an function and returns it.
 */
expADT readF(scannerADT scanner){
	expADT exp;
	string token;

	token = ReadToken(scanner);
	if(StringEqual(token, "(")){
		exp = readE(scanner);
		if (!StringEqual(ReadToken(scanner), ")")) {
			Error("Unbalanced parentheses");
        }
	} else if(isdigit(IthChar(token, 0))){
		exp = NewIntegerExp(StringToInteger(token));
	} else if(StringEqual(token,"if")){
		exp = parseIf(scanner);
	} else if(StringEqual(token,"func")){
		exp = parseFunc(scanner);
	} else if(isalpha(IthChar(token,0))){
		exp = NewIdentifierExp(token);
	} else{
		Error("Illegal function in expression");
	}
	
	return exp;
}

/*
 * Function: parseFunc
 * Usage: exp = parseFunc(scanner);
 * ------------------------------
 * This function parse a function call and returns it.
 */
static expADT parseFunc(scannerADT scanner){
	expADT body;
	string token,arg;
	arg ="";

	token = ReadToken(scanner);
	if(StringEqual(token, "(")){
		token = ReadToken(scanner);
		if(isalpha(IthChar(token,0)))
			arg = CopyString(token); 
		else
			Error("Illegal function argument");
		if (!StringEqual(ReadToken(scanner), ")")) {
			Error("Unbalanced parentheses");
		}
	} 
	else{
		Error("Illegal function");
	}

	token = ReadToken(scanner);
	if(StringEqual(token, "{")){
		body = readE(scanner);
		if (!StringEqual(ReadToken(scanner), "}")) {
			Error("Unbalanced brackets");
		}
	}
	else{
		Error("Illegal function");
	}
		
	return NewFuncExp(arg, body);

}

/*
 * Function: parseIf
 * Usage: exp = parseIf(scanner);
 * ------------------------------
 * This function parse an ifexpression and returns it.
 */
static expADT parseIf(scannerADT scanner){
	expADT lhs, rhs, thenPart, elsePart;
	char relOp;
	string token;

	lhs = readE(scanner);
	token = ReadToken(scanner);

	if(isRelOp(token))
		relOp = IthChar(token,0);
	else
		Error("Illegal RelOp in If-expression");

	rhs = readE(scanner);

	token = ReadToken(scanner);
	if(StringEqual(token, "then"))
		thenPart = readE(scanner);
	else
		Error("Illegal thenPart in If-expression");

	token = ReadToken(scanner);
	if(StringEqual(token, "else"))
		elsePart = readE(scanner);
	else
		Error("Illegal elsePart in If-expression");

	return NewIfExp(lhs, relOp, rhs, thenPart, elsePart);

}

/*
 * Function: isRelOp
 * Usage: if(isRelOp(scanner));
 * ------------------------------
 * This function check the token if it is a relOp or not.
 */
static bool isRelOp(string token){
	if(StringLength(token) != 1)
		return FALSE;
	
	switch(IthChar(token,0)){
		case '=': case '<': case '>':
			return TRUE;
		default:
			return FALSE;
	}
}